package CentralServ;

import java.io.Serializable;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import org.omg.CORBA.ORB;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;

import util.Constants;
import util.ModelParser;

import CarroServ.CarroRPC_cln;
import CarroServ.Carros;
import corba.ClienteServ.ClienteServ;
import corba.ClienteServ.ClienteServHelper;

public class CentralServ extends UnicastRemoteObject implements ICentralServ {

	public static void main(String[] args) {
	   try {
		   System.out.println("Iniciando o servidor central.");
		   CentralServ obj = new CentralServ();
	       Naming.rebind(String.format("//%s/%s",Constants.IP_SERVIDOR_CENTRAL, Constants.NOME_SERVIDOR_CENTRAL), obj);
	       System.out.println("Servidor central inicizalizado com sucesso!");
	   } catch (Exception ex) {
	        System.err.println("ERRO no servidor central: " + ex);
	        ex.printStackTrace(System.out);
	   } 
	}
	
   private CarroRPC_cln carroServer;
   private ClienteServ clienteServer;
   private HashMap<String, ArrayList<Locacao>> locacoes = new HashMap<String, ArrayList<Locacao>>();
   
   public CentralServ() throws Exception {
	   super();
	   //inicia o servidor dos carros
	   carroServer = new CarroRPC_cln(Constants.IP_SERVIDOR_CARRO, "tcp");
	   
	   //incia o servidor dos clientes
      ORB orb = ORB.init(new String[0], null);
      org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
      NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
      String name = Constants.NOME_SERVIDOR_CLIENTE;
      clienteServer = ClienteServHelper.narrow(ncRef.resolve_str(name));
   }
	   
	@Override
	public void cadastrarCarro(Carro carro) throws RemoteException {
		try {
			carroServer.cadastrar(ModelParser.parse(carro));
		} catch(Exception ex) {
			System.err.println("Ocorre um erro vindo do servidor de carros: ");
			ex.printStackTrace();
		}
	}

	@Override
	public void removerCarro(String placa) throws RemoteException {
		try {
			Carro carro = new Carro();
			carro.placa = placa;
			carroServer.remover(ModelParser.parse(carro));
		} catch(Exception ex) {
			System.err.println("Ocorre um erro vindo do servidor de carros: ");
			ex.printStackTrace();
		}
	}
	
	@Override
	public void cadastrarCliente(Cliente cliente) throws RemoteException {
		clienteServer.cadastrar(ModelParser.parse(cliente));
	}


	@Override
	public void removerCliente(String cpf) throws RemoteException {
		clienteServer.remover(cpf);
		
	}

	@Override
	public List<Carro> selecionarCarrosDisponiveis(Date dataInicio)
			throws RemoteException {
		List<Carro> carrosDisponiveis = new LinkedList<Carro>();
		Carros carros;
		
		try {
			carros = carroServer.selecionarTodos();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		
		if(carros == null)
			return null;
		
		proximoCarro: for (CarroServ.Carro carro : carros.value) {
			List<Locacao> locacoesCarroCorrente = locacoes.get(carro.placa);
			
			if(locacoesCarroCorrente == null)
				continue proximoCarro;
			
			for (Locacao locacao : locacoesCarroCorrente) {
				if(dataInicio.before(locacao.getFim()) && dataInicio.after(locacao.getInicio()))
					continue proximoCarro;
			}
			carrosDisponiveis.add(ModelParser.parse(carro));
		}
		
		return carrosDisponiveis;
	}

	@Override
	public Carro getCarroPelaPlaca(String placa) throws RemoteException {
		try {
			return ModelParser.parse(carroServer.selecionarPorPlaca(placa));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public void alugarCarro(Date dataInicio, Date dataFim, Carro carro,
			Cliente cliente, double valor) throws RemoteException {
		Locacao novaLocacao = new Locacao();
		novaLocacao.setCarro(carro);
		novaLocacao.setCliente(cliente);
		novaLocacao.setInicio(dataInicio);
		novaLocacao.setFim(dataFim);
		novaLocacao.setValor(valor);
		
		ArrayList<Locacao> locacoesFeitas = locacoes.get(carro.placa);
		
		locacoesFeitas.add(novaLocacao);
		
		locacoes.put(carro.placa, locacoesFeitas);
	}

	@Override
	public Cliente getClientePeloCpf(String cpf) throws RemoteException {
		return ModelParser.parse(clienteServer.seleciona(cpf));
	}

	@Override
	public List<Cliente> selecionaClientes() throws RemoteException {
		List<Cliente> retorno = new LinkedList<Cliente>();
		
		for(corba.ClienteServ.Cliente cliente : clienteServer.selecionaTodos()) {
			retorno.add(ModelParser.parse(cliente));
		}
		
		return retorno;
	}

	@Override
	public List<Carro> selecionaCarros() throws RemoteException {
		List<Carro> retorno = new LinkedList<Carro>();
		
		try {
			for(CarroServ.Carro carro : carroServer.selecionarTodos().value) {
				retorno.add(ModelParser.parse(carro));
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return retorno;
	}

	
}
